﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using StarsAdmin.Core.Cache;
using StarsAdmin.Core.Consts;
using StarsAdmin.Core.Helpers;
using StarsAdmin.Core.Models;
using System.Security.Claims;
using System.Text.Encodings.Web;

namespace StarsAdmin.Core.JWT
{
    /// <summary>
    /// Api响应认证处理器
    /// </summary>
    public class ApiResponseHandler : AuthenticationHandler<AuthenticationSchemeOptions>
    {
        private readonly ICacheService _cache;

        public ApiResponseHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ICacheService cache, ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder)
        {
            _cache = cache;
        }

        /// <summary>
        /// 验证身份
        /// </summary>
        /// <returns></returns>
        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            // 验证请求头是否携带Authorization
            var authorization = Request.Headers.ContainsKey("Authorization");
            if (!authorization)
            {
                return AuthenticateResult.NoResult();
            }
            // 验证token是否存在
            var authHeader = Request.Headers["Authorization"].ToString().Split(" ");
            if (authHeader.Length != 2 || !authHeader[0].Equals("Bearer", StringComparison.OrdinalIgnoreCase))
            {
                return AuthenticateResult.NoResult();
            }
            var token = authHeader[1];
            var flag = JwtHelper.ValidateAccessToken(token, out ClaimsPrincipal? principal, out _);
            if (!flag && principal == null)
            {
                Context.Items.TryAdd(CacheKeyConst.AuthMessageKey, "无效的令牌，请重新登录");
                return AuthenticateResult.Fail("");
            }
            // 验证当前用户是否存在
            var userId = JwtHelper.GetUserId(token);
            if (userId != default)
            {
                Context.Items.TryAdd(CacheKeyConst.AuthMessageKey, "无效的令牌，请重新登录");
                return AuthenticateResult.Fail("");
            }
            // 验证token版本是否正确
            var version = JwtHelper.GetTokenVersion(token);
            var cacheVersion = await _cache.GetAsync<string>(userId, CacheKeyConst.TokenVersionKey);
            if (version != cacheVersion)
            {
                Context.Items.TryAdd(CacheKeyConst.AuthMessageKey, "令牌已过期，请重新登录");
                return AuthenticateResult.Fail("");
            }
            // 如果Token验证成功，则创建Ticket
            var ticket = new AuthenticationTicket(
                principal,
                Scheme.Name);
            return AuthenticateResult.Success(ticket);
        }

        /// <summary>
        /// 401,没有登录走这里
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
        {
            Response.ContentType = "application/json";
            Response.StatusCode = StatusCodes.Status401Unauthorized;
            Context.Items.TryGetValue(CacheKeyConst.AuthMessageKey, out object? value);
            await Response.WriteAsync(JsonConvert.SerializeObject(ResultModel<object>.Error(value?.ToString() ?? "对不起，请先登录!", 401)));
        }

        /// <summary>
        /// 403,已登录，但是没有权限的走这里
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
        {
            Response.ContentType = "application/json";
            Response.StatusCode = StatusCodes.Status403Forbidden;
            await Response.WriteAsync(JsonConvert.SerializeObject(ResultModel<object>.Error("对不起，你没有所需的权限!", 403)));
        }
    }
}